Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

EVG-19946: Support Docker on provider settings page #2017

Merged
merged 12 commits into from
Sep 18, 2023

Conversation

minnakt
Copy link
Contributor

@minnakt minnakt commented Sep 1, 2023

EVG-19946

Description

This PR adds Docker to the provider settings page. The Docker configuration is kind of weird (container pool ID is not part of provider settings list) so I made some changes in the form schema and conversion functions.

Screenshots

Screenshot 2023-09-01 at 11 00 13 AM

Testing

  • Cypress tests, Jest tests

Evergreen PR

@minnakt minnakt marked this pull request as ready for review September 1, 2023 16:09
@minnakt minnakt requested a review from a team September 1, 2023 16:09
cy.getInputByLabel("User Data").type("my user data");
cy.getInputByLabel("Merge with existing user data").check({
force: true,
describe.only("docker", () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
describe.only("docker", () => {
describe("docker", () => {

@@ -71,6 +70,7 @@ import PROJECT_HEALTH_VIEW from "./project-health-view.graphql";
import GET_PROJECT_PATCHES from "./project-patches.graphql";
import GET_SPAWN_EXPIRATION_INFO from "./spawn-expiration.graphql";
import GET_SPAWN_TASK from "./spawn-task.graphql";
import GET_SPRUCE_CONFIG from "./spruce-config.graphql";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've been removing GET_ from the import/export name too

Suggested change
import GET_SPRUCE_CONFIG from "./spruce-config.graphql";
import SPRUCE_CONFIG from "./spruce-config.graphql";

providerName: Provider.Docker,
},
providerSettings: {
...dockerProviderSettings(providerSettingsList[0]).form,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched the localhost distro to use Docker and then tried to switch it back to static and saw this error:
image

It seems like there's validation here preventing container pool distros from using a different provider.

Maybe someone on app would have insight into the best approach here. Do we want to ban Docker distros from having their types changed? Or do we maybe want to update the save function to remove this distro from the list of Docker distros? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh that's probably my fault. Have to clear the containerPool field in the transformers

providerSettingsList: [
...dockerProviderSettings(data.providerSettings).gql,
],
// @ts-ignore-error - containerPoolId will exist in DockerFormState.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can narrow down the type here using the in operator to avoid this error (docs). Something like this:

    case Provider.Docker: {
      if ("containerPoolId" in data.providerSettings) {
        return {
          ...distro,
          provider: Provider.Docker,
          providerSettingsList: [
            ...dockerProviderSettings(data.providerSettings).gql,
          ],
          containerPool: data.providerSettings.containerPoolId,
        };
      }
      break;
    }

@SupaJoon
Copy link
Contributor

SupaJoon commented Sep 8, 2023

evergreen retry

Comment on lines 17 to 28
const { pools = [] } = containerPools || {};

const selectedPoolId = formData?.providerSettings?.containerPoolId;
const selectedPool = pools.find((p) => p.id === selectedPoolId) ?? null;
const poolMappingInfo = selectedPool
? JSON.stringify(omitTypename(selectedPool), null, 4)
: "";

const formSchema = useMemo(
() => getFormSchema({ pools, poolMappingInfo }),
[pools, poolMappingInfo]
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The useMemo will run on every render when pools is undefined. You can avoid doing that by casting pools to an array closer to where it's used. Another place to cast pools is in getFormSchema which is good if the function were reused so we only have to type cast in one place.

Suggested change
const { pools = [] } = containerPools || {};
const selectedPoolId = formData?.providerSettings?.containerPoolId;
const selectedPool = pools.find((p) => p.id === selectedPoolId) ?? null;
const poolMappingInfo = selectedPool
? JSON.stringify(omitTypename(selectedPool), null, 4)
: "";
const formSchema = useMemo(
() => getFormSchema({ pools, poolMappingInfo }),
[pools, poolMappingInfo]
);
const { pools } = containerPools || {};
const selectedPoolId = formData?.providerSettings?.containerPoolId;
const selectedPool = pools?.find((p) => p.id === selectedPoolId) ?? null;
const poolMappingInfo = selectedPool
? JSON.stringify(omitTypename(selectedPool), null, 4)
: "";
const formSchema = useMemo(
() => getFormSchema({ pools: pools || [], poolMappingInfo }),
[pools, poolMappingInfo]
);

@cypress
Copy link

cypress bot commented Sep 13, 2023

Passing run #12763 ↗︎

0 584 7 0 Flakiness 0
⚠️ You've recorded test results over your free plan limit.
Upgrade your plan to view test results.

Details:

Update SpruceConfig mock to contain container pools
Project: Spruce Commit: e3ee2db36d
Status: Passed Duration: 17:54 💡
Started: Sep 18, 2023 9:02 PM Ended: Sep 18, 2023 9:20 PM

This comment has been generated by cypress-bot as a result of this project's GitHub integration settings.

@minnakt
Copy link
Contributor Author

minnakt commented Sep 14, 2023

hello hello, so after experimenting a bit with the EC2 providers, I ended up concluding that maybe we should just have unique fields for each provider (rather than trying to share the providerSettings field across all four providers). This solution will require us to redeclare some fields, but I think it might be simpler overall.

I first tried a more "elegant" solution where the providerSettings field would be an array in the schema, and we would populate the array with the appropriate amount of items (1 item for Static, 1 item for Docker, 4 items for EC2). This didn't work out so well due to a specific scenario:

  1. Start out with EC2 provider with 4 items in the array (each item corresponds to an AWS region)
  2. Switch to the Static provider
  3. You'd still have 4 items in the array, which is wrong for Static providers

And this is why I ended up thinking that it would be simpler for each of the providers to have their own fields. Lmk what you think! 😲

Pull = "pull",
}

// TODO: Append type with additional provider options, e.g. type ProviderFormState = StaticProviderFormState | DockerProviderFormState
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] I think this no longer applies in the way it's written here, could update or just remove.

import { BaseTab } from "../BaseTab";
import { getFormSchema } from "./getFormSchema";
import { TabProps } from "./types";
import { TabProps, ProviderFormState } from "./types";

export const ProviderTab: React.FC<TabProps> = ({ distroData }) => {
const initialFormState = distroData;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] No need to rename this var (even though I think we have been doing it unnecessarily in every tab 😂)

},
],
};
describe("docker provider", () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding a test that uses the poolMappingInfo field?

buildType: BuildType;
registryUsername: string;
registryPassword: string;
containerPoolId: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like poolMappingInfo could also be a field here no?

@@ -30,27 +32,88 @@ const getSecurityGroups = ((providerSettings) => ({
},
})) satisfies FieldGetter;

const getImageUrl = ((providerSettings) => ({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we somehow indicate that providerSettings represents 2 different types of objects with TypeScript types? It will also be helpful if we can type the providerSettings from the API based on usage in Spruce so we know what to expect from the object.

type ProviderSettings = ProviderFormState["staticProviderSettings"] &
ProviderFormState["dockerProviderSettings"];

export const gqlProviderSettings = (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This structure makes a lot more sense 😅 gorgeous!

* Because if you switch from static -> docker you need to update a bunch of fields, versus switch from docker -> static
Copy link
Contributor

@SupaJoon SupaJoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done!!! 😎

@minnakt minnakt changed the title EVG-19946: Add Docker to provider settings page EVG-19946: Support Docker on provider settings page Sep 18, 2023
@minnakt minnakt changed the title EVG-19946: Support Docker on provider settings page EVG-19946: Add support for Docker on provider settings page Sep 18, 2023
@minnakt minnakt changed the title EVG-19946: Add support for Docker on provider settings page EVG-19946: Support Docker on provider settings page Sep 18, 2023
@minnakt minnakt merged commit 372a1e0 into evergreen-ci:main Sep 18, 2023
2 checks passed
@minnakt minnakt deleted the EVG-19946 branch September 18, 2023 22:10
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants